Skip to content

feat(cua-driver-rs)(macos): enable Chromium/Electron AX trees (AXManualAccessibility) for get_window_state#1756

Merged
f-trycua merged 1 commit into
mainfrom
feat/ax-chromium-enablement
May 31, 2026
Merged

feat(cua-driver-rs)(macos): enable Chromium/Electron AX trees (AXManualAccessibility) for get_window_state#1756
f-trycua merged 1 commit into
mainfrom
feat/ax-chromium-enablement

Conversation

@f-trycua
Copy link
Copy Markdown
Collaborator

@f-trycua f-trycua commented May 29, 2026

Problem

Chromium-based apps (Arc, VS Code, Electron shells) ship their web-content accessibility tree off and only build it once an assistive client requests it. Without enablement, the first get_window_state AX walk of such an app returns an empty / title-bar-only tree — the macOS/AX analog of the empty-tree symptom tracked in #1616 (VS Code exposing only its title-bar elements). With enablement the full tree materializes.

Change

In walk_tree's app-setup path (right after AXUIElementCreateApplication(pid)):

  1. Enable — set AXManualAccessibility = true on the app root (the modern, side-effect-free opt-in). If the app reports the attribute unsupported (kAXErrorAttributeUnsupported / -25205), fall back to AXEnhancedUserInterface = true (the legacy flag some Electron builds expose instead). Native Cocoa apps (Finder, Calculator, TextEdit) reject both — they take no further action.
  2. Settle — the tree is built asynchronously over IPC once the app detects the client, so a walk that starts immediately still sees only the chrome. When the flip actually took, pump the run loop ~500ms (reusing the existing pump_run_loop_briefly helper) so the tree has time to materialize before the walk reads it.
  3. Per-pid cache — a process-global HashSet<pid> (guarded by a Mutex in a OnceLock) records pids we've already enabled + settled. Repeat snapshots of the same app skip the settle; the tree is already built and stays built for the life of the process.

The settle delay fires only when enablement actually flips an app from unsupported→supported, so apps that never needed it (every native Cocoa app) pay zero added latency.

Hard dependency

This is intentionally higher-risk and must land after the Phase 1 messaging-timeout PR. Enablement makes the tree bigger (fully materialized instead of empty/partial) — which is exactly why it depends on the per-element AX messaging timeout (so a wedged element fails fast rather than stalling the now-larger walk) plus the node cap to keep the materialized tree bounded. Shipping this without those bounds would trade "empty/partial" for "complete but potentially huge."

Test

  • cargo build --release -p cua-driver passes.
  • cargo test --no-run -p platform-macos compiles cleanly (the crate's test binary has a pre-existing, unrelated libswift_Concurrency.dylib rpath issue at the run step only).
  • macOS-only change; platform-windows / platform-linux are untouched.

Refs #1616

🤖 Generated with Claude Code

Summary by CodeRabbit

  • Bug Fixes
    • Improved accessibility support for Chromium and Electron-based applications on macOS. The system now properly enables accessibility features and allows adequate initialization time, preventing incomplete or missing accessibility information when first accessing these applications and improving overall reliability.

@vercel
Copy link
Copy Markdown
Contributor

vercel Bot commented May 29, 2026

The latest updates on your projects. Learn more about Vercel for GitHub.

1 Skipped Deployment
Project Deployment Actions Updated (UTC)
docs Ignored Ignored Preview May 29, 2026 4:38pm

Request Review

@coderabbitai
Copy link
Copy Markdown
Contributor

coderabbitai Bot commented May 29, 2026

Review Change Stack

Caution

Review failed

The pull request is closed.

ℹ️ Recent review info
⚙️ Run configuration

Configuration used: Organization UI

Review profile: CHILL

Plan: Pro

Run ID: 774bc777-f775-4063-b29b-ac78b94eb94e

📥 Commits

Reviewing files that changed from the base of the PR and between 73a84f5 and d9491d3.

📒 Files selected for processing (2)
  • libs/cua-driver/rust/crates/platform-macos/src/ax/bindings.rs
  • libs/cua-driver/rust/crates/platform-macos/src/ax/tree.rs

📝 Walkthrough

Walkthrough

This PR adds Chromium/Electron accessibility support to the macOS AX driver. A new enable_chromium_accessibility helper attempts to write accessibility attributes, and the AX tree walker integrates it with a per-process settle delay to allow the system time to prepare AX snapshots after enablement.

Changes

Chromium accessibility enablement

Layer / File(s) Summary
Accessibility enablement helper
libs/cua-driver/rust/crates/platform-macos/src/ax/bindings.rs
enable_chromium_accessibility tries to set AXManualAccessibility and falls back to AXEnhancedUserInterface on unsupported-attribute errors.
Per-process settle mechanism
libs/cua-driver/rust/crates/platform-macos/src/ax/tree.rs
Added imports for synchronization primitives, a CHROMIUM_SETTLE_SECONDS delay constant, and a process-lifetime enabled_pids() helper that caches PIDs. The walk_tree function now calls enable_chromium_accessibility once per PID before building the tree and pumps the CF run loop to settle.

Estimated code review effort

🎯 3 (Moderate) | ⏱️ ~25 minutes

Poem

🐰 A rabbit hops through Chromium's door,
Writes attributes, settles, and then explores more,
Per-process caches dance with the delay,
AX trees now bloom in the right way! 🌳

✨ Finishing Touches
📝 Generate docstrings
  • Create stacked PR
  • Commit on current branch
🧪 Generate unit tests (beta)
  • Create PR with unit tests
  • Commit unit tests in branch feat/ax-chromium-enablement

Thanks for using CodeRabbit! It's free for OSS, and your support helps us grow. If you like it, consider giving us a shout-out.

❤️ Share

Comment @coderabbitai help to get the list of available commands and usage tips.

…_window_state

Chromium/Electron apps (Arc, VS Code, Electron shells) ship their web-content
accessibility tree off and only build it once an assistive client requests it.
Without enablement the first AX walk returns an empty/title-bar-only tree.

Flip AXManualAccessibility (modern, side-effect-free) on the application root,
falling back to AXEnhancedUserInterface when the modern attribute is
unsupported. When the flip actually takes, let the asynchronously-built tree
settle (~500ms run-loop pump) before walking. Cache per-pid so repeat snapshots
skip the settle. Native Cocoa apps reject the attribute and pay no cost.

Co-Authored-By: Claude Opus 4.8 (1M context) <noreply@anthropic.com>
@f-trycua f-trycua force-pushed the feat/ax-chromium-enablement branch from df5ddd5 to d9491d3 Compare May 29, 2026 16:38
@f-trycua f-trycua marked this pull request as ready for review May 31, 2026 15:11
@f-trycua f-trycua merged commit 88f87eb into main May 31, 2026
10 checks passed
@f-trycua f-trycua deleted the feat/ax-chromium-enablement branch May 31, 2026 15:11
f-trycua added a commit that referenced this pull request May 31, 2026
- Add 0.4.2: macOS 14 Sonoma SkyLight selector guard (#1782, #1503) and
  Chromium/Electron AX trees via AXManualAccessibility (#1756).
- Fix the 0.3.6 entry, which described the permissions-status fix backwards:
  it now reports the driver's grants (via the daemon), not the caller's.

Co-authored-by: Claude Opus 4.8 <noreply@anthropic.com>
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment

Labels

None yet

Projects

None yet

Development

Successfully merging this pull request may close these issues.

1 participant